#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "audio_element.h"
#include "audio_pipeline.h"
#include "audio_event_iface.h"
#include "audio_common.h"
#include "audio_mem.h"

#include "http_stream.h"
#include "fatfs_stream.h"
#include "i2s_stream.h"
#include "mp3_decoder.h"
#include "wav_decoder.h"

#include "esp_audio.h"

#include "sdcard_list.h"
#include "sdcard_scan.h"
#include "audio_sys.h"

#include "esp_peripherals.h"
#include "periph_wifi.h"
#include "board.h"

#include "app_music_play.h"
#include "app_mqtt_client.h"

#include "cJSON.h"

#include <ctype.h>

static const char *TAG = "app.music";

esp_audio_handle_t               player;

playlist_operator_handle_t       playlist;
static int                              auto_play_type;

static void music_play_task(void * parm);

static void sdcard_url_save_cb(void *user_data, char *url)
{
    playlist_operator_handle_t sdcard_handle = (playlist_operator_handle_t)user_data;
    esp_err_t ret = sdcard_list_save(sdcard_handle, url);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Fail to save sdcard url to sdcard playlist");
    }
}

//static esp_err_t cli_play(esp_periph_handle_t periph, int argc, char *argv[])
//audio_err_t esp_audio_play(esp_audio_handle_t handle, audio_codec_type_t type, const char *uri, int pos);
esp_err_t app_audio_play(const char *uri,  int pos)
{
    ESP_LOGI(TAG, "app audio play");
    char *str = NULL;

    if (uri != NULL) 
    {
        if (isdigit((int)uri[0])){
            int index = atoi(uri);
            if (index >= sdcard_list_get_url_num(playlist)) {
                ESP_LOGE(TAG, "Out of range, index:%d", index);
                return ESP_ERR_INVALID_ARG;
            }
            sdcard_list_choose(playlist, index, &str);
        }else{
            str = uri;
        }

    } else {
        sdcard_list_current(playlist, &str);
        if (str == NULL) {
            ESP_LOGE(TAG, "No URI to tone play");
            return ESP_ERR_INVALID_ARG;
        }
    }

    esp_audio_play(player, AUDIO_CODEC_TYPE_DECODER, str, pos);
    return ESP_OK;
}

esp_err_t app_audio_pause(void)
{
    esp_audio_pause(player);
    ESP_LOGI(TAG, "app audio paused");
    return ESP_OK;
}

esp_err_t app_audio_resume(void)
{
    esp_audio_resume(player);
    ESP_LOGI(TAG, "app audio resume");
    return ESP_OK;
}

esp_err_t app_audio_stop(void)
{
    esp_audio_stop(player, 0);
    ESP_LOGI(TAG, "app audio stop");
    return ESP_OK;
}

esp_err_t app_audio_set_vol(int vol)
{
    int prev_vol = 0;
    esp_audio_vol_get(player, &prev_vol);
    esp_audio_vol_set(player, vol);
    ESP_LOGI(TAG, "Volume setting changed from %d to %d", prev_vol, vol);
    return ESP_OK;
}


esp_err_t app_audio_get_list(char** data)
{
#define LIST_GET_NUM_MAX 5
#define LIST_SONG_URL_SIZE_MAX 256
#define LIST_JSON_BUFF_SIZE_MAX 500
    cJSON* root = NULL;
    cJSON* song_list = NULL;

    uint8_t i = 0;

    char* url;
    char* json_print;

    root = cJSON_CreateObject();
    song_list = cJSON_CreateArray();

    while (i < LIST_GET_NUM_MAX)
    {
        /* code */
        if(sdcard_list_choose(playlist, i++, &url) == ESP_FAIL)
            break;

        cJSON_AddItemToArray(song_list, cJSON_CreateString(url));
    }

    cJSON_AddItemToObject(root, "list", song_list);
    cJSON_AddNumberToObject(root, "num", i);

    json_print = cJSON_Print(root);


    ESP_LOGI(TAG, "song list json:%s", json_print);

    cJSON_Delete(root);
    *data = json_print;

    return ESP_OK;
}

esp_err_t app_audio_get_vol(int* vol)
{
    esp_audio_vol_get(player, vol);
    return ESP_OK;
}

esp_err_t app_audio_playlist_sd_scan(const char *path)
{
    sdcard_list_reset(playlist);
    sdcard_scan(sdcard_url_save_cb, path,
    0, (const char *[]) {"mp3", "wav"}, 2, playlist);
    sdcard_list_show(playlist);
    return ESP_OK;
}

esp_err_t app_audio_playlist_sd_show(void)
{
    sdcard_list_show(playlist);  
    return ESP_OK; 
}

esp_err_t app_audio_playlist_sd_next(int step)
{
    char *url = NULL;
    sdcard_list_next(playlist, step, &url);
    esp_audio_play(player, AUDIO_CODEC_TYPE_DECODER, url, 0);
    return ESP_OK;
}

esp_err_t app_audio_playlist_sd_prev(int step)
{
    char *url = NULL;
    sdcard_list_prev(playlist, step, &url);
    esp_audio_play(player, AUDIO_CODEC_TYPE_DECODER, url, 0);
    return ESP_OK;
}

bool app_audio_is_runing(void)
{
    esp_audio_state_t state_temp;
    esp_audio_state_get(player, &state_temp);

    if(state_temp.status == AUDIO_STATUS_RUNNING)
        return 1;
    else
        return 0;

    return 0;
}

static void esp_audio_state_task (void *para)
{
    QueueHandle_t que = (QueueHandle_t) para;
    esp_audio_state_t esp_state = {0};
    while (1) {
        xQueueReceive(que, &esp_state, portMAX_DELAY);
        ESP_LOGI(TAG, "esp_auido status:%x,err:%x\n", esp_state.status, esp_state.err_msg);

        mqtt_publish_state_pack();

        if ((esp_state.status == AUDIO_STATUS_FINISHED)
            || (esp_state.status == AUDIO_STATUS_ERROR)) {
            int time = 0;
            int duration = 0;
            esp_audio_time_get(player, &time);
            esp_audio_duration_get(player, &duration);
            ESP_LOGI(TAG, "[ * ] End of time:%d ms, duration:%d ms", time, duration);
            AUDIO_MEM_SHOW(TAG);
            if (auto_play_type) {
                char *url = NULL;
                if (sdcard_list_next(playlist, 1, &url) == ESP_OK) {
                    ESP_LOGI(TAG, "play index= %d, URI:%s, byte_pos:%d", sdcard_list_get_url_id(playlist), url, 0);
                    esp_audio_play(player, AUDIO_CODEC_TYPE_DECODER, url, 0);
                }
            }
        }
    }
    vTaskDelete(NULL);
}

void initialise_music(void)
{
    if (player ) {
        return ;
    } 
    esp_audio_cfg_t cfg = DEFAULT_ESP_AUDIO_CONFIG();
    audio_board_handle_t board_handle = audio_board_init();
    cfg.vol_handle = board_handle->audio_hal;
    cfg.vol_set = (audio_volume_set)audio_hal_set_volume;
    cfg.vol_get = (audio_volume_get)audio_hal_get_volume;
    cfg.prefer_type = ESP_AUDIO_PREFER_MEM;
    cfg.resample_rate = 48000;
    cfg.evt_que = xQueueCreate(3, sizeof(esp_audio_state_t));
    player = esp_audio_create(&cfg);
    audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);
    xTaskCreate(esp_audio_state_task, "player_task", 2*4096, cfg.evt_que, 1, NULL);

    fatfs_stream_cfg_t fs_reader = FATFS_STREAM_CFG_DEFAULT();
    fs_reader.type = AUDIO_STREAM_READER;

    esp_audio_input_stream_add(player, fatfs_stream_init(&fs_reader));

    mp3_decoder_cfg_t  mp3_dec_cfg  = DEFAULT_MP3_DECODER_CONFIG();
    wav_decoder_cfg_t  wav_dec_cfg  = DEFAULT_WAV_DECODER_CONFIG();

    esp_audio_codec_lib_add(player, AUDIO_CODEC_TYPE_DECODER, mp3_decoder_init(&mp3_dec_cfg));
    esp_audio_codec_lib_add(player, AUDIO_CODEC_TYPE_DECODER, wav_decoder_init(&wav_dec_cfg));

    i2s_stream_cfg_t i2s_writer = I2S_STREAM_CFG_DEFAULT();
    i2s_writer.i2s_config.sample_rate = 48000;
    i2s_writer.i2s_config.mode = I2S_MODE_MASTER | I2S_MODE_TX;
    i2s_writer.type = AUDIO_STREAM_WRITER;

    audio_element_handle_t i2s_h =  i2s_stream_init(&i2s_writer);

    esp_audio_output_stream_add(player, i2s_h);

    // Set default volume
    esp_audio_vol_set(player, 35);
    AUDIO_MEM_SHOW(TAG);
    ESP_LOGI(TAG, "esp_audio instance is:%p\r\n", player);

    sdcard_list_create(&playlist);

    app_audio_playlist_sd_scan("/sdcard");


}

